namespace classifier_test
{

namespace high_drift
{

struct kalman_filter
{
	double X, N, DecayRate;

	void init();
	void measure(double Z);
	double guess() const;
};

class high_drift_classifier : public stream_classifier
{
public:
	high_drift_classifier();
	high_drift_classifier(const high_drift_classifier& Val);
	smart_ptr<stream_classifier> clone() const;
	int get_build_chunk_size() const;
	void set_build_chunk_size(int Val);

	void build(subarray<const stream_record* const> Data);
	void train(const stream_record& LabeledRecord);
	void estimate(const stream_record& Record, array<double>& Probs) const;
	int get_concept_count() const;
	const array<double>& get_concept_accuracies() const;

protected:
	void initialize_options(command_line_options& Options) const;
	void apply_arguments(const command_line_arguments& Args);

private:
	struct concept
	{
		smart_ptr<classifier> Classifier;
		kalman_filter Filter;
	};

	struct chunk
	{
		subarray<const record* const> Data;
		smart_ptr<classifier> Classifier;
		concept* Concept;
	};

	int BuildChunkSize;

	subarray<const stream_record* const> TrData;
	vector<smart_ptr<chunk> > Chunks;
	vector<smart_ptr<concept> > Concepts;
	array<double> ConAccus;

	void compute_chunks();
	void compute_chunk_similarities(vector<vector<float> >& Matrix) const;
	void compute_concepts();
	void compute_concept_classifiers();
	void compute_filters();

	void tune_filter(concept* Concept);
	void tune_filter_param(concept* Concept, subarray<const char> Hits, double Delta);
	double error_of_filter(concept* Concept, subarray<const char> Hits);
};

}

using high_drift::high_drift_classifier;

}
